﻿using System;
using StockModel;
using Utils.Wpf;

namespace StockAnalyst2.StockGrid
{
	internal class RowVM : ViewModelBase, IDisposable
	{
		#region Attributes

		private bool _isSelected;
		private bool _isVisible;

		private readonly object _initializationLock;

		#endregion

		#region Properties

		public QuotationDailyInfo Model { get; private set; }

		public CellStringVM Group { get; private set; }
		public CellStringVM Name { get; private set; }
		public CellStringVM Symbol { get; private set; }
		public CellDecimalVM Value { get; private set; }
		public CellDecimalVM OpenDifference { get; private set; }
		public CellDecimalVM PreviousDifference { get; private set; }
		public CellIntegerVM BidVolume { get; private set; }
		public CellDecimalVM Bid { get; private set; }
		public CellDecimalVM Ask { get; private set; }
		public CellIntegerVM AskVolume { get; private set; }
		public CellDecimalVM GapDifference { get; private set; }
		public CellDecimalVM BidAskAverage { get; private set; }
		public CellDecimalVM Max { get; private set; }
		public CellDecimalVM Min { get; private set; }
		public CellIntegerVM LastVolume { get; private set; }
		public CellIntegerVM TotalVolume { get; private set; }
		public CellTimeSpanVM LastOperation { get; private set; }
		public CellDecimalVM MaxDifference { get; private set; }
		public CellDecimalVM MinDifference { get; private set; }
		public CellDecimalVM OpenValue { get; private set; }
		public CellDecimalVM PreviousDayValue { get; private set; }
		public CellStringVM Status { get; private set; }
		public CellDateTimeVM Date { get; private set; }

		public bool IsSelected
		{
			get
			{
				return _isSelected;
			}
			set
			{
				if (_isSelected != value)
				{
					_isSelected = value;
					base.OnPropertyChanged("IsSelected");
				}
			}
		}

		public bool IsVisible
		{
			get
			{
				return _isVisible;
			}
			set
			{
				if (_isVisible != value)
				{
					_isVisible = value;
					base.OnPropertyChanged("IsVisible");
				}
			}
		}

		#endregion

		#region Public Methods

		public RowVM(string group, string name, string symbol, QuotationDailyInfo model)
		{
			_initializationLock = new object();

			lock (_initializationLock)
			{
				this.Model = model;
				this.Model.DailyKeyQuotations.PropertyChanged += this.DailyKeyQuotations_PropertyChanged; // Disposed
				this.Model.DailyStatistics.PropertyChanged += this.DailyStatistics_PropertyChanged; // Disposed

				this.Group = new CellStringVM() { Value = group };
				this.Name = new CellStringVM() { Value = name };
				this.Symbol = new CellStringVM() { Value = symbol };
				this.Value = new CellDecimalVM();
				this.OpenDifference = new CellDecimalVM();
				this.PreviousDifference = new CellDecimalVM();
				this.BidVolume = new CellIntegerVM();
				this.Bid = new CellDecimalVM();
				this.Ask = new CellDecimalVM();
				this.AskVolume = new CellIntegerVM();
				this.GapDifference = new CellDecimalVM();
				this.BidAskAverage = new CellDecimalVM();
				this.Max = new CellDecimalVM();
				this.Min = new CellDecimalVM();
				this.LastVolume = new CellIntegerVM();
				this.TotalVolume = new CellIntegerVM();
				this.LastOperation = new CellTimeSpanVM();
				this.MaxDifference = new CellDecimalVM();
				this.MinDifference = new CellDecimalVM();
				this.OpenValue = new CellDecimalVM();
				this.PreviousDayValue = new CellDecimalVM();
				this.Status = new CellStringVM();
				this.Date = new CellDateTimeVM();
			}
		}

		#endregion

		#region Event Handlers

		private void DailyStatistics_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			lock (_initializationLock)
			{
				if (e.PropertyName == "OpenDiffPercentage")
				{
					this.OpenDifference.Value = this.Model.DailyStatistics.OpenDiffPercentage;
				}
				else if (e.PropertyName == "PreviousDayDiffPercentage")
				{
					this.PreviousDifference.Value = this.Model.DailyStatistics.PreviousDayDiffPercentage;
				}
				else if (e.PropertyName == "GapDifferencePercentage")
				{
					this.GapDifference.Value = this.Model.DailyStatistics.GapDifferencePercentage;
				}
				else if (e.PropertyName == "BidAskAverage")
				{
					this.BidAskAverage.Value = this.Model.DailyStatistics.BidAskAverage;
				}
				else if (e.PropertyName == "LastVolume")
				{
					this.LastVolume.Value = this.Model.DailyStatistics.LastVolume;
				}
				else if (e.PropertyName == "LastOperation")
				{
					this.LastOperation.Value = this.Model.DailyStatistics.LastOperation;
				}
				else if (e.PropertyName == "MaxOpenDifferencePercentage")
				{
					this.MaxDifference.Value = this.Model.DailyStatistics.MaxOpenDifferencePercentage;
				}
				else if (e.PropertyName == "MinOpenDifferencePercentage")
				{
					this.MinDifference.Value = this.Model.DailyStatistics.MinOpenDifferencePercentage;
				}
			}
		}

		private void DailyKeyQuotations_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			lock (_initializationLock)
			{
				if (e.PropertyName == "LastQuotation")
				{
					this.Value.Value = this.Model.DailyKeyQuotations.LastQuotation.Value;
					this.BidVolume.Value = this.Model.DailyKeyQuotations.LastQuotation.Buyers[0].Quantity;
					this.AskVolume.Value = this.Model.DailyKeyQuotations.LastQuotation.Sellers[0].Quantity;
					this.Bid.Value = this.Model.DailyKeyQuotations.LastQuotation.Buyers[0].Value;
					this.Ask.Value = this.Model.DailyKeyQuotations.LastQuotation.Sellers[0].Value;
					this.TotalVolume.Value = this.Model.DailyKeyQuotations.LastQuotation.Volume;
					this.Status.Value = this.Model.DailyKeyQuotations.LastQuotation.Type.ToString();
					this.Date.Value = this.Model.DailyKeyQuotations.LastQuotation.Date;
				}
				else if (e.PropertyName == "Max")
				{
					this.Max.Value = this.Model.DailyKeyQuotations.Max.Value;
				}
				else if (e.PropertyName == "Min")
				{
					this.Min.Value = this.Model.DailyKeyQuotations.Min.Value;
				}
				else if (e.PropertyName == "Opening")
				{
					this.OpenValue.Value = this.Model.DailyKeyQuotations.Opening.Value;
				}
				else if (e.PropertyName == "PreviousClosing")
				{
					this.PreviousDayValue.Value = this.Model.DailyKeyQuotations.PreviousClosing.Value;
				}
			}
		}

		#endregion

		#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				this.Model.DailyKeyQuotations.PropertyChanged -= this.DailyKeyQuotations_PropertyChanged;
				this.Model.DailyStatistics.PropertyChanged -= this.DailyStatistics_PropertyChanged;
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~RowVM()
		{
			this.Dispose(false);
		}

		#endregion
	}
}